package com.imy.rootserver.helper;

import android.os.SystemClock;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;

import androidx.test.uiautomator.Configurator;

import com.imy.rootserver.bean.GesturePoint;

import java.util.ArrayList;
import java.util.List;

public class MotionEventHelper {
  private String TAG = "MotionEventHelper";
  private static final int MAX_GESTURE = 10;
  private static MotionEventHelper gCore = new MotionEventHelper();
  private List<GesturePoint> pointList = new ArrayList<>();
  private long downTime;
  private static final int UN_KNOW = -1;

  public static MotionEventHelper get() {
    return gCore;
  }

  public MotionEvent createEvent(GesturePoint point) {
    if (pointList.size() >= MAX_GESTURE) {
      //Log.i(TAG, "当前超过10个手势,返回");
      return null;
    }
    addPoint(point);
    int index = pointList.size() - 1;
    return getMotionEvent(pointList.get(index), index);
  }

  private static MotionEvent getSingleMotionEvent(long downTime, long eventTime, int action,
      float x, float y, int id) {

    MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
    properties.id = id;
    properties.toolType = MotionEvent.TOOL_TYPE_FINGER;

    MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
    coords.pressure = 1;
    coords.size = 1;
    coords.x = x;
    coords.y = y;

    return MotionEvent.obtain(downTime, eventTime, action, 1,
        new MotionEvent.PointerProperties[] { properties }, new MotionEvent.PointerCoords[] { coords },
        0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
  }

  private MotionEvent getMotionEvent(GesturePoint trigger_point, int index) {
    Log.i(TAG,"getMotionEvent:"+trigger_point.toString()+" index");
    if (pointList.size() == 1) {
      GesturePoint point = pointList.get(0);
      return getSingleMotionEvent(downTime, downTime, point.action, point.x, point.y, point.id);
    }
    Log.i(TAG, pointList.size() + "个手指进入");
    return createMultiMotionEvent(trigger_point, index);
  }

  /**
   * @param trigger_point 当前进入的手指
   * @param index         当前的索引
   * @return
   */
  private MotionEvent createMultiMotionEvent(GesturePoint trigger_point, int index) {
    MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[pointList.size()];
    MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointList.size()];
    for (int i = 0; i < pointList.size(); i++) {
      // 查找缓存
      GesturePoint point = pointList.get(i);
      //重新注入当前手势
      //downtime 代表按下的事件 如果是第一次按下 eventtime 就是downtime //后续每次注入都需要生成新的eventtime
      // 注入id
      MotionEvent.PointerProperties prop = new MotionEvent.PointerProperties();
      prop.id = i;
      prop.toolType = Configurator.getInstance().getToolType();
      properties[i] = prop;
      MotionEvent.PointerCoords pointerCoord = new MotionEvent.PointerCoords();
      pointerCoord.x = point.getX();
      pointerCoord.y = point.getY();
      pointerCoord.size = 1; //接触面积
      pointerCoord.pressure = 1;//按压 压力
      pointerCoords[i] = pointerCoord;
    }
    int action = changePointTypeToAction(trigger_point.action, index);
    if (action == UN_KNOW) {
      return null;
    }
    MotionEvent obtain = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), action, pointList.size(), properties,
        pointerCoords, 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
    Log.i(TAG, "手势事件:" + obtain);
    return obtain;
  }

  private int getPointerAction(int motionEnvent, int index) {
    return motionEnvent + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
  }

  private int changePointTypeToAction(int action, int last_index) {
    if (action == MotionEvent.ACTION_DOWN) {
      return getPointerAction(MotionEvent.ACTION_POINTER_DOWN, last_index);
    } else if (action == MotionEvent.ACTION_UP) {
      return getPointerAction(MotionEvent.ACTION_POINTER_UP, last_index);
    }else if (action==MotionEvent.ACTION_MOVE){
      return action;
    }
    return UN_KNOW;
  }

  private void addPoint(GesturePoint point) {
    //判断当前是第几个手指
    int size = pointList.size();
    if (size == 0) {
      //当前无手指 按下的是第一个手指 需记录按下时间downTime
      Log.i(TAG, "当前为第一个手势 ，记录按下时间");
      downTime = SystemClock.uptimeMillis();
    }
    //为手势创建id
    pointList.add(point);
  }

  public synchronized MotionEvent releasedMotionEvent(GesturePoint targetPoint) {
    //取出对应手势的缓存
    //需判断当前缓存了几个手指
    if (pointList.size() == 1) {
      GesturePoint point = pointList.get(0);
      long point_down_time = point.point_down_time;
      MotionEvent singleMotionEvent = getSingleMotionEvent(point_down_time,
          SystemClock.uptimeMillis(), targetPoint.action, point.x, point.y, point.id);
      pointList.remove(point);
      return singleMotionEvent;
    } else {
        Object[] objects = setTargetPointReleased(targetPoint);//即将释放的键位//注入事件
        if (objects != null) {
            GesturePoint point = (GesturePoint) objects[0];
            int index = (int) objects[1];
            MotionEvent multiMotionEvent = createMultiMotionEvent(point, index);
            //在移除缓存手势;
            pointList.remove(point);
            return multiMotionEvent;
        }
        return null;
    }
  }

  private Object[] setTargetPointReleased(GesturePoint targetPoint) {
      Object[] objects = new Object[2];
    for (int i = 0; i < pointList.size(); i++) {
      GesturePoint point = pointList.get(i);
      if (point.id == targetPoint.id) { //缓存得到的类型释放
        point.x = targetPoint.x;
        point.y = targetPoint.y;
        point.action = targetPoint.action;
          objects[0] = point;
          objects[1] = i;
          return objects;
      }
    }
    return null;
  }

  public MotionEvent onMove(GesturePoint point) {
    int index = -1;
    for (int i = 0; i < pointList.size(); i++) {
      GesturePoint gesturePoint = pointList.get(i);
      //获取上一次的
      if (gesturePoint.id == point.id) {
        gesturePoint.action = point.action;
        gesturePoint.x = point.x;
        gesturePoint.y = point.y;
        index = i;
        break;
      }
    }
    Log.i(TAG,"onMove index:"+index+" point:"+point.toString());
    if (index != -1) {
      return getMotionEvent(point, index);
    }
    return null;
  }
}
